// =================GeoJSON TO ESRIJSON======================================  
function geoJSONToEsriJSON() {  
    const gCon = {};  

    /*compares a GeoJSON geometry type and ESRI geometry type to see if they can be safely 
     put together in a single ESRI feature. ESRI features must only have one 
     geometry type, point, line, polygon*/  
    function isCompatible(esriGeomType, gcGeomType) {  
        let compatible = false;  
        if ((esriGeomType === 'esriGeometryPoint' || esriGeomType === 'esriGeometryMultipoint')  
            && (gcGeomType === 'Point' || gcGeomType === 'MultiPoint')) {  
            compatible = true;  
        } else if (esriGeomType === 'esriGeometryPolyline' &&  
            (gcGeomType === 'LineString' || gcGeomType === 'MultiLineString')) {  
            compatible = true;  
        } else if (esriGeomType === 'esriGeometryPolygon' &&  
            (gcGeomType === 'Polygon' || gcGeomType === 'MultiPolygon')) {  
            compatible = true;  
        }  
        return compatible;  
    }  

    /*Take a GeoJSON geometry type and make an object that has information about 
     what the ESRI geometry should hold. Includes the ESRI geometry type and the name 
     of the member that holds coordinate information*/  
    function gcGeomTypeToEsriGeomInfo(gcType) {  
        let esriType,  
            geomHolderId;  
        if (gcType === 'Point') {  
            esriType = 'esriGeometryPoint';  
        } else if (gcType === 'MultiPoint') {  
            esriType = 'esriGeometryMultipoint';  
            geomHolderId = 'points';  
        } else if (gcType === 'LineString' || gcType === 'MultiLineString') {  
            esriType = 'esriGeometryPolyline';  
            geomHolderId = 'paths';  
        } else if (gcType === 'Polygon' || gcType === 'MultiPolygon') {  
            esriType = 'esriGeometryPolygon';  
            geomHolderId = 'rings';  
        }  
        return {  
            type: esriType,  
            geomHolder: geomHolderId  
        };  
    }  

    // Convert GeoJSON polygon coordinates to ESRI polygon coordinates  
    function gcPolygonCoordinatesToEsriPolygonCoordinates(gcCoords) {  
        let i,  
            len;  
        const esriCoords = [];  
        let ring;  
        for (i = 0, len = gcCoords.length; i < len; i++) {  
            ring = gcCoords[i];  
            // Exclusive OR.  
            if ((i === 0) !== ringIsClockwise(ring)) {  
                ring = ring.reverse();  
            }  
            esriCoords.push(ring);  
        }  
        return esriCoords;  
    }  
    /*rings is Clockwise or not 
    */  
    function ringIsClockwise(ring) {  
        let sum = 0;  
        let i = 1;  
        const len = ring.length;  
        let prev, cur;  
        while (i < len) {  
            prev = cur || ring[0];  
            cur = ring[i];  
            sum += ((cur[0] - prev[0]) * (cur[1] + prev[1]));  
            i++;  
        }  
        return sum > 0;  
    }  

    /*Wraps GeoJSON coordinates in an array if necessary so code can iterate 
     through array of points, rings, or lines and add them to an ESRI geometry 
     Input is a GeoJSON geometry object. A GeoJSON GeometryCollection is not a 
     valid input */  
    function gcCoordinatesToEsriCoordinates(gcGeom) {  
        let i,  
            len,  
            esriCoords;  
        if (gcGeom.type === 'MultiPoint' || gcGeom.type === 'MultiLineString') {  
            esriCoords = gcGeom.coordinates || [];  
        } else if (gcGeom.type === 'Point' || gcGeom.type === 'LineString') {  
            esriCoords = gcGeom.coordinates ? [gcGeom.coordinates] : [];  
        } else if (gcGeom.type === 'Polygon') {  
            esriCoords = [];  
            if (gcGeom.coordinates) {  
                esriCoords = gcPolygonCoordinatesToEsriPolygonCoordinates(gcGeom.coordinates);  
            }  
        } else if (gcGeom.type === 'MultiPolygon') {  
            esriCoords = [];  
            if (gcGeom.coordinates) {  
                for (i = 0, len = gcGeom.coordinates.length; i < len; i++) {  
                    const a = gcPolygonCoordinatesToEsriPolygonCoordinates(gcGeom.coordinates[i]);  
                    esriCoords.push(a[0]);  
                }  
            }  
        }  
        return esriCoords;  
    }  

    /*Converts GeoJSON geometry to ESRI geometry. The ESRI geometry is 
     only allowed to contain one type of geometry, so if the GeoJSON 
     geometry is a GeometryCollection, then only geometries compatible 
     with the first geometry type in the collection are added to the ESRI geometry 
     Input parameter is a GeoJSON geometry object.*/  
    function gcGeometryToEsriGeometry(gcGeom) {  
        let esriGeometry,  
            esriGeomInfo,  
            gcGeometriesToConvert,  
            i,  
            g,  
            coords;  

        // if geometry collection, get info about first geometry in collection  
        if (gcGeom.type === 'GeometryCollection') {  
            const geomCompare = gcGeom.geometries[0];  
            gcGeometriesToConvert = [];  
            esriGeomInfo = gcGeomTypeToEsriGeomInfo(geomCompare.type);  

            // loop through collection and only add compatible geometries to the array  
            // of geometries that will be converted  
            for (i = 0; i < gcGeom.geometries.length; i++) {  
                if (isCompatible(esriGeomInfo.type, gcGeom.geometries[i].type)) {  
                    gcGeometriesToConvert.push(gcGeom.geometries[i]);  
                }  
            }  
        } else {  
            esriGeomInfo = gcGeomTypeToEsriGeomInfo(gcGeom.type);  
            gcGeometriesToConvert = [gcGeom];  
        }  

        // if a collection contained multiple points, change the ESRI geometry  
        // type to MultiPoint  
        if (esriGeomInfo.type === 'esriGeometryPoint' && gcGeometriesToConvert.length > 1) {  
            esriGeomInfo = gcGeomTypeToEsriGeomInfo('MultiPoint');  
        }  

        // make new empty ESRI geometry object  
        esriGeometry = {  
            // type: esriGeomInfo.type,  
            spatialReference: {  
                wkid: 4326  
            }  
        };  

        // perform conversion  
        if (esriGeomInfo.type === 'esriGeometryPoint') {  
            if (!gcGeometriesToConvert[0] || !gcGeometriesToConvert[0].coordinates ||  
                gcGeometriesToConvert[0].coordinates.length === 0) {  
                esriGeometry.x = null;  
            } else {  
                esriGeometry.x = gcGeometriesToConvert[0].coordinates[0];  
                esriGeometry.y = gcGeometriesToConvert[0].coordinates[1];  
            }  
        } else {  
            esriGeometry[esriGeomInfo.geomHolder] = [];  
            for (i = 0; i < gcGeometriesToConvert.length; i++) {  
                if (gcGeometriesToConvert.length > 1) {  
                    coords = gcCoordinatesToEsriCoordinates(gcGeometriesToConvert[i]);  
                    for (g = 0; g < coords.length; g++) {  
                        esriGeometry[esriGeomInfo.geomHolder].push(coords[g]);  
                    }  

                } else {  
                    coords = gcCoordinatesToEsriCoordinates(gcGeometriesToConvert[i]);  
                    for (g = 0; g < coords.length; g++) {  
                        esriGeometry[esriGeomInfo.geomHolder].push(coords[g]);  
                    }  
                }  
            }  
        }  
        return esriGeometry;  
    }  

    // Converts GeoJSON feature to ESRI REST Feature.  
    //  Input parameter is a GeoJSON Feature object  
    function gcFeatureToEsriFeature(gcFeature) {  
        let esriFeat,  
            esriAttribs;  
        if (gcFeature) {  
            esriFeat = {};  
            if (gcFeature.geometry) {  
                esriFeat.geometry = gcGeometryToEsriGeometry(gcFeature.geometry);  
            }  
            if (gcFeature.properties) {  
                esriAttribs = {};  
                for (const prop in gcFeature.properties) {  
                    if (gcFeature.properties.hasOwnProperty(prop)) {  
                        esriAttribs[prop] = gcFeature.properties[prop];  
                    }  
                }  
                esriFeat.attributes = esriAttribs;  
            }  
        }  
        return esriFeat;  
    }  

    /*Converts GeoJSON FeatureCollection, Feature, or Geometry 
     to ESRI Rest Featureset, Feature, or Geometry*/  
    gCon.toEsri = function (geoJsonObject) {  
        let outObj,  
            i,  
            gcFeats,  
            esriFeat;  
        if (geoJsonObject) {  
            if (geoJsonObject.type === 'FeatureCollection') {  
                outObj = {  
                    features: []  
                };  
                gcFeats = geoJsonObject.features;  
                for (i = 0; i < gcFeats.length; i++) {  
                    esriFeat = gcFeatureToEsriFeature(gcFeats[i]);  
                    if (esriFeat) {  
                        outObj.features.push(esriFeat);  
                    }  
                }  
            } else if (geoJsonObject.type === 'Feature') {  
                outObj = gcFeatureToEsriFeature(geoJsonObject);  
            } else {  
                outObj = gcGeometryToEsriGeometry(geoJsonObject);  
            }  
        }  
        return outObj;  
    };  

    return gCon;  
}  

export default geoJSONToEsriJSON